#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import bz2
import os
import unittest

import crypto
import safe

PLAIN = (u'This is a Teststring with german umlauts (äöü) and signs '
         u'(!"§$%&)'.encode('utf-8'))
PASSWD = u'secret'
SALT = u'salt'


class CryptoTest(unittest.TestCase):

    def test_simple(self):
        encrypted = crypto.encrypt(PLAIN, PASSWD, algorithm=self.algo)
        self.assertEqual(PLAIN, crypto.decrypt(encrypted, PASSWD,
                                               algorithm=self.algo))

    def test_with_salt(self):
        encrypted = crypto.encrypt(PLAIN, PASSWD, SALT, algorithm=self.algo)
        self.assertEqual(PLAIN, crypto.decrypt(encrypted, PASSWD, SALT,
                                               algorithm=self.algo))

    def test_with_vs_without_salt(self):
        encrypted1 = crypto.encrypt(PLAIN, PASSWD, SALT, algorithm=self.algo)
        encrypted2 = crypto.encrypt(PLAIN, PASSWD, algorithm=self.algo)
        self.assertNotEqual(encrypted1, encrypted2)

    def test_passwords(self):
        encrypted1 = crypto.encrypt(PLAIN, PASSWD, SALT, algorithm=self.algo)
        encrypted2 = crypto.encrypt(PLAIN, u'Secret', SALT, algorithm=self.algo)
        self.assertNotEqual(encrypted1, encrypted2)

    def test_content(self):
        encrypted1 = crypto.encrypt(u'test', PASSWD, SALT, algorithm=self.algo)
        encrypted2 = crypto.encrypt(u'Test', PASSWD, SALT, algorithm=self.algo)
        self.assertNotEqual(encrypted1, encrypted2)

    def test_binary(self):
        encrypted = crypto.encrypt(bz2.compress(PLAIN), PASSWD, SALT,
            algorithm=self.algo)
        self.assertEqual(PLAIN, bz2.decompress(crypto.decrypt(encrypted,
            PASSWD, SALT, algorithm=self.algo)))

    def test_rounds(self):
        encrypted1 = crypto.encrypt(PLAIN, PASSWD, algorithm=self.algo)
        encrypted2 = crypto.encrypt(PLAIN, PASSWD, rounds=12,
                                    algorithm=self.algo)
        self.assertNotEqual(encrypted1, encrypted2)


class AESTest(CryptoTest):
    algo = 'AES'


class BlowfishTest(CryptoTest):
    algo = 'Blowfish'


class TwofishTest(CryptoTest):
    algo = 'Twofish'


class KeySafeTest(unittest.TestCase):

    testfile = 'unittest.pickle'

    def setUp(self):
        self.ks = safe.KeySafe(PASSWD, self.testfile)
        self.ks.sync(PASSWD)

    def tearDown(self):
        if os.path.isfile(self.testfile):
            os.remove(self.testfile)

    def test_write_safefile(self):
        self.assertTrue(os.path.isfile(self.testfile))

    def test_encrypt_decrypt(self):
        self.ks.add(PASSWD, u'Facebook', u'Username', u'secret')
        uname, pw = self.ks.get(PASSWD, u'Facebook')
        self.assertEqual(uname, 'Username')

    def test_wrong_password(self):
        self.ks.add('secret', u'Facebook', u'Username', u'Password')
        uname, pw = self.ks.get('Secret', u'Facebook')
        self.assertNotEqual(pw, 'Password')

    def test_unknown_service(self):
        self.assertRaises(KeyError, self.ks.get, PASSWD, 'myservice')

    def test_wrong_category(self):
        self.ks.add(PASSWD, u'Mail', u'User', u'Pass', u'Cat')
        self.assertRaises(KeyError, self.ks.get, PASSWD, 'Mail', 'cat')


if __name__ == '__main__':
    suite = [
        unittest.TestLoader().loadTestsFromTestCase(AESTest),
        unittest.TestLoader().loadTestsFromTestCase(BlowfishTest),
        unittest.TestLoader().loadTestsFromTestCase(TwofishTest),
        unittest.TestLoader().loadTestsFromTestCase(KeySafeTest),
    ]
    alltests = unittest.TestSuite(suite)
    unittest.TextTestRunner(verbosity=2).run(alltests)
